package org.example.netty.test.nio.java;

import lombok.extern.slf4j.Slf4j;
import org.example.netty.test.bio.NioDemoConfig;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * @author zp
 * @version 1.0
 * @description: 测试SocketChannel的方法
 * @date 2023/2/20 19:46
 */
@Slf4j
public class SocketChannelDemo {
    private Charset charset = StandardCharsets.UTF_8;

    public static void main(String[] args) throws IOException {
        SocketChannelDemo socketChannelDemo = new SocketChannelDemo();
        socketChannelDemo.sendFile();
    }

    /**
     * @description: 向服务器端传输文件
     * @author zp
     * @date: 2023/2/20 19:52
     */
    public void sendFile() throws IOException {

            String sourcePath = NioDemoConfig.SOCKET_SEND_FILE;
            String srcPath = IOUtil.getResourcePath(sourcePath);
            log.debug("srcPath=" + srcPath);
            String destFile = NioDemoConfig.SOCKET_RECEIVE_FILE;
            log.debug("destFile=" + destFile);
            File file = new File(srcPath);
            if (!file.exists()) {
                log.debug("文件不存在");
                return;
            }

            FileChannel fileChannel = new FileInputStream(file).getChannel();
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.socket().connect(new InetSocketAddress("127.0.0.1", 18899));
            socketChannel.configureBlocking(false);
            log.debug("Client 成功连接服务端");
            while (!socketChannel.finishConnect()) {
               log.debug("等待服务器连接");
            }
            //发送文件名称和长度
            ByteBuffer buffer = sengFileNameAndLength(destFile, file, socketChannel);
            //发送文件内容
            int length = sendContent(file, fileChannel, socketChannel, buffer);
            if (length == -1) {
                IOUtil.closeQuietly(fileChannel);
                socketChannel.shutdownOutput();
                IOUtil.closeQuietly(socketChannel);
            }
            log.debug("======== 文件传输成功 ========");

    }

    /**
     * @param file
     * @param fileChannel
     * @param socketChannel
     * @param buffer
     * @return int
     * @description: 发送文件内容
     * @author zp
     * @date: 2023/2/20 19:54
     */
    public int sendContent(File file, FileChannel fileChannel, SocketChannel socketChannel, ByteBuffer buffer) throws IOException {
        //发送文件内容
        log.debug("开始传输文件");
        int length = 0;
        long progress = 0;
        while ((length = fileChannel.read(buffer)) > 0) {
            buffer.flip();
            socketChannel.write(buffer);
            buffer.clear();
            progress += length;
            log.debug("| " + (100 * progress / file.length()) + "% |");
        }
        return length;
    }
    /**
     * @description: 发送文件名称和长度
     * @author zp
     * @date: 2023/2/20 19:58
     * @param destFile
     * @param file
     * @param socketChannel
     * @return ByteBuffer
     */
    public ByteBuffer sengFileNameAndLength(String destFile, File file, SocketChannel socketChannel) throws IOException {
        //发送文件名称
        ByteBuffer fileNameByteBuffer = charset.encode(destFile);
        ByteBuffer buffer = ByteBuffer.allocate(NioDemoConfig.SEND_BUFFER_SIZE);
        //发送文件名称长度
        int fileNameLen = fileNameByteBuffer.capacity();
        buffer.putInt(fileNameLen);
        buffer.flip();
        socketChannel.write(buffer);
        buffer.clear();
        log.info("Client 文件名称长度发送完成:{}", fileNameLen);

        //发送文件名称
        socketChannel.write(fileNameByteBuffer);
        log.info("Client 文件名称发送完成:{}", destFile);
        //发送文件长度
        buffer.putLong(file.length());
        buffer.flip();
        socketChannel.write(buffer);
        buffer.clear();
        log.info("Client 文件长度发送完成:{}", file.length());
        return buffer;
    }
}
